﻿import * as chartjsExt from "../../js/chartjs-ext.js";

export function createChart(chartCanvasId, csThis, datasets, aspectEnum) {
    let domCanvas = document.getElementById(chartCanvasId);
    if (domCanvas == null)
        return;
    domCanvas.aspectEnum = aspectEnum;

    let chartConfig = {
        type: 'line',
        data: {
            labels: []
        },
        options: {
            animation: false,
            maintainAspectRatio: false,
            interaction: {
                // Overrides the global setting
                mode: 'index',
                intersect: false
            },
            scales: {
                x: {
                    type: "linear",
                },
                y: {
                    beginAtZero: false,
                    title: {
                        display: true,
                        text: aspectEnum == 0 ? '-/-' : (aspectEnum == 1 ? 'um' : '--'),
                        //font: {
                        //    size: 15
                        //}
                    },
                    ticks: {
                        callback: function (value) {
                            if (domCanvas.aspectEnum == 0) {
                                return (value * 100).toFixed(0) + '%'; // convert it to percentage
                            }
                            else {
                                return parseFloat(Number(value).toPrecision(2));
                            }
                        }
                    }
                }
            },

            onResize: async function (chart, dim) {
                //console.log(chart);
                if (chart.ext != undefined)
                    await csThis.invokeMethodAsync('UpdateDataByClStripOnce');
            },
            onHover: async function (evt, item, chart) {
                //console.log('evt',evt);
                //console.log('item',item);
                //console.log(chart.scales.x.getValueForPixel(evt.x));

                let xDim = chart.scales.x.max - chart.scales.x.min;
                chart.ext.xPositionPercentage
                    = (chart.scales.x.getValueForPixel(evt.x) - chart.scales.x.min) / xDim;

                if (item.length)
                    await csThis.invokeMethodAsync('EnterStripPos', item[0].index);
            },
            onClick: async function (evt, item, chart) {
                //console.log(evt);
                //console.log(item);
                //console.log(chart);
                if (item.length)
                    await csThis.invokeMethodAsync('SelectStripPos', item[0].index);
            },
            plugins: {
                legend: {
                    display: true,
                    labels: {
                        filter: (legendItem, chartData) => {
                            //console.log('legendItem', legendItem);
                            //console.log('chartData', chartData);
                            return legendItem.datasetIndex % 2 == 0;
                        }
                    },
                    onClick: function (e, legendItem) {
                        var index = legendItem.datasetIndex;
                        var ci = this.chart;
                        //console.log('legendItem', legendItem);
                        //console.log('ci.getDatasetMeta(index)', ci.getDatasetMeta(index));
                        ci.getDatasetMeta(index).hidden = !(ci.getDatasetMeta(index).hidden);
                        ci.getDatasetMeta(index + 1).hidden = !(ci.getDatasetMeta(index + 1).hidden);
                        try {
                            ci.update();
                        }
                        catch (ex) { }
                    }
                },
                tooltip: {
                    callbacks: {
                        title: function (context) {
                            if (!context[0].chart.ext.is_xaxis_time_category) {
                                let dst = '';
                                if (context[0].dataIndex > 0 && context[0].chart.ext.is_xaxis_range_mode)
                                    dst += context[0].chart.data.labels[context[0].dataIndex - 1] + ' ~ ';
                                dst += context[0].label;
                                return dst;
                            }
                            let dst = '';
                            if (context[0].dataIndex > 0 && context[0].chart.ext.is_xaxis_range_mode)
                                dst += chartjsExt.toStopWatchTimeDetailString(
                                    context[0].chart.data.labels[context[0].dataIndex - 1]) + ' ~ ';
                            dst = dst + chartjsExt.toStopWatchTimeDetailString(context[0].parsed.x);
                            return dst;
                        },
                        label: function (context) {
                            if (context.datasetIndex % 2 == 1)
                                return null;
                            //console.log('context', context);
                            const datasets = context.chart.data.datasets;
                            let minValue = datasets[context.datasetIndex].data[context.dataIndex];
                            let maxValue = datasets[context.datasetIndex + 1].data[context.dataIndex];
                            let minValueText = null;
                            let maxValueText = null;
                            if (domCanvas.aspectEnum == 0) {
                                minValueText = `${(minValue * 100).toFixed(2)}%`;
                                maxValueText = `${(maxValue * 100).toFixed(2)}%`;
                            }
                            else {
                                minValueText = parseFloat(Number(minValue).toPrecision(2));
                                maxValueText = parseFloat(Number(maxValue).toPrecision(2));
                            }

                            if (minValueText != maxValueText)
                                return `${context.dataset.label}: ${minValueText} ~ ${maxValueText}`;
                            return `${context.dataset.label}: ${minValueText}`;
                        }
                    }
                }
            }
        },
        plugins: [{
            id: 'hoverOut',
            beforeEvent(chart, args, pluginOptions) {
                const event = args.event;
                if (event.type === 'mouseout') {
                    csThis.invokeMethodAsync('EnterStripPos', -1).then();
                }
            }
        }]
    };
    let chart = new Chart(domCanvas, chartConfig);
    domCanvas.chart = chart;
    chart.ext = {
        is_xaxis_time_category: false,
        is_xaxis_range_mode: true,
    };
    chart.options.scales.x.ticks.callback = function (value, index, ticks) {
        if (!chart.ext.is_xaxis_time_category)
            return value;

        let v = value;
        if (!Number.isFinite(v))
            return;
        return chartjsExt.toStopWatchTimeString(v);
    };

    domCanvas.chart.data.datasets = datasets;

    regChartCallback(chart, csThis);
    //console.log(chart);
}

let localRegCallbackResult = null;
function regChartCallback(chart, csThis) {
    let funcVisibleChanged = async function () {
        await csThis.invokeMethodAsync('VisibleChanged', document.visibilityState);
    }
    document.addEventListener('visibilitychange', funcVisibleChanged);

    //set passive false to avoid chrome scroll bar invocation.
    let funcMouseWheelXyz = async function (e) {
        e.preventDefault();

        let xPositionPercentage = chart.ext.xPositionPercentage;
        if (xPositionPercentage === undefined)
            return;

        //chart.ext.lastMouseMoveEvent
        await csThis.invokeMethodAsync('MouseWheel', e.deltaX, e.deltaY, e.deltaZ,
            xPositionPercentage);
    };
    //console.log(chart);
    chart.canvas?.addEventListener('mousewheel', funcMouseWheelXyz, { passive: false });

    localRegCallbackResult = {
        chart: chart,
        funcVisibleChanged: funcVisibleChanged,
        funcMouseWheelXyz: funcMouseWheelXyz
    };
}
export function dispose() {
    if (localRegCallbackResult) {
        document.removeEventListener('visibilitychange', localRegCallbackResult.funcVisibleChanged);
        localRegCallbackResult.chart.canvas?.removeEventListener('mousewheel', localRegCallbackResult.funcMouseWheelXyz);
        localRegCallbackResult.chart.options.onResize = null;
        localRegCallbackResult.chart.options.onHover = null;
        localRegCallbackResult.chart.options.onClick = null;
    }
}


export function setChartData(chartCanvasId, xs, ys, renderedItemEnumLength,
    is_xaxis_time_category, is_xaxis_range_mode) {
    let domCanvas = document.getElementById(chartCanvasId);
    if (domCanvas == null)
        return;
    let chart = domCanvas.chart;
    //console.log("setChartData", domCanvas, domCanvas.chart);
    //console.log(xs);
    //console.log(ymins);

    if (xs.length > 0) {
        chart.options.scales.x.min = xs[0];
        //console.log("setChartData.B");
        chart.options.scales.x.max = xs.slice(-1);
    }
    //console.log("setChartData.C");
    if (chart.data == null) {
        console.error("setChartData failed: chart.data is null or undefined.");
        return;
    }
    if (is_xaxis_range_mode)
        chart.data.datasets.forEach(dataset => dataset.pointRadius = 0);
    else
        chart.data.datasets.forEach(dataset => dataset.pointRadius = 1);
    //console.log("setChartData.D");
    //console.log('a', chart, 'b', chart.data);
    chart.data.labels = xs;

    for (let itemIndex = 0; itemIndex < renderedItemEnumLength; itemIndex++) {
        chart.data.datasets[itemIndex * 2].data = ys[itemIndex][0];
        chart.data.datasets[itemIndex * 2 + 1].data = ys[itemIndex][1];
    }

    chart.ext.is_xaxis_range_mode = is_xaxis_range_mode;
    chart.ext.is_xaxis_time_category = is_xaxis_time_category;
    //    console.log(xs);
    //    console.log(chart.data.labels);
    //console.log("Plu.setChartData.E");
}

export function setChartVRange(chartCanvasId, vmin, vmax) {
    let domCanvas = document.getElementById(chartCanvasId);
    if (domCanvas == null)
        return;
    let chart = domCanvas.chart;
    //console.log('a');
    //console.log(vmin);
    //console.log(vmax);
    chart.options.scales.y.min = vmin;
    chart.options.scales.y.max = vmax;
    try {
        chart.update();
        //console.log("Plu.setChartVRange.E");
    }
    catch (ex) { }
}

//get chart plotting area width.
export function getChartAreaWidth(chartCanvasId) {
    let domCanvas = document.getElementById(chartCanvasId);
    //console.log(domCanvas?.chart);
    return domCanvas?.chart?.chartArea?.width ?? 0;
}
export function getCanvasDivWidth(chartCanvasId) {
    let domCanvas = document.getElementById(chartCanvasId);
    //console.log(domCanvas.offsetWidth);
    return domCanvas?.offsetWidth ?? 0;
}

export function triggerHover(chartCanvasId, chartPointIndex) {
    let domCanvas = document.getElementById(chartCanvasId);
    if (domCanvas == null)
        return;
    let chart = domCanvas.chart;
    //console.log(chartPointIndex);
    if (chartPointIndex > -1) {
        let dst = chart.data.datasets.map((dataset, i) => ({
            datasetIndex: i,
            index: chartPointIndex,
        }));
        //the triggerHover might be called before data init,
        //it occurs: TypeError: Cannot set properties of undefined (setting 'active')
        //ignore the error here.
        try {
            chart.setActiveElements(dst);
            const tooltip = chart.tooltip;
            tooltip.setActiveElements(dst);
            chart.update();
        } catch (ex) { }
    }
    else {
        try {
            chart.setActiveElements([]);
            const tooltip = chart.tooltip;
            tooltip.setActiveElements([]);
            chart.update();
        } catch (ex) { }
    }

}
